Vector Field Visualization and Data Recovery

Vector Field Visualization and Data Recovery

  1. ggvfields
  2. Data Recovery
  3. Conclusion

ggvfields

  1. Introduction of Problem
  2. Current Solutions
  3. Proposed Solutions ggvfields

Before we define the problem

What is a vector field?

  • Definition: A function mapping each point \((x, y)\) to a vector in the plane.
  • Mathematical Representation:
    • \(\mathbf{V}: \mathbb{R}^2 \rightarrow \mathbb{R}^2\)
    • \(\mathbf{V}(x, y) = (u(x, y), v(x, y))\)
  • Components:
    • \((u(x, y), v(x, y))\): Vector assigned to point \((x, y)\)

Before we define the problem

There are many applications across various fields:

  1. Physics:
    • Representing force fields (gravitational, electric, magnetic)
    • Describing the velocity field of particles in a fluid flow
  2. Engineering:
    • Modeling airflow over wings and around vehicles
    • Modeling water flow in hydrology
  3. Meteorology:
    • Mapping wind velocities
    • Mapping ocean currents
  1. Mathematics:
    • Gradient of scalar-valued functions
    • Partial derivatives
  2. Statistics:
    • Gradient descent optimization
    • Exploratory data analysis

How do we visualize a vector field?

\[\mathbf{f}(x,y) = (-y, x)\]

mulitvariate

note: pull out multivarious calculus book to show what a real one looks like

The Problem: R

f <- function(v) {
  x <- v[1]; y <- v[2]
  c(-y, x) # = f(x,y)
}

x <- seq(-10, 10, by = 1)
y <- seq(-10, 10, by = 1)

df <- expand_grid(x = x, y = y) 

df_v <- df |> apply(1, f) |> t() |> as_tibble() |> rename(u = y, v = x)

bind_cols(df, df_v) |> 

ggplot(aes(x = x, y = y)) +
  geom_segment(
    aes(xend = x + u, yend = y + v), 
    arrow = arrow(length = unit(0.1, "cm"))
    ) 

The Problem: R

The Problem: R

  • Excessive syntax
  • High user burden
  • Difficult to customize
  • Unattractive results
  • Not informative

Current Solutions: Python

Question: I could not find a python version where it takes in a function. I could engineer it but not where it takes a function argument. U and V are functions.

import numpy as np
import matplotlib.pyplot as plt

# Create a grid of points
x = np.linspace(-10, 10, 20)
y = np.linspace(-10, 10, 20)
X, Y = np.meshgrid(x, y)

# Define the vector field
U = -Y
V = X

# Plot the vector field
plt.quiver(X, Y, U, V)

Current Solutions: Python

Current Solutions: Mathematica

f[x_, y_] := {-y, x}
VectorPlot[f[x, y], {x, -3, 3}, {y, -3, 3}]

Proposed Solutions: ggvfields

Requirements

  • Correct
  • Attractive
  • Simple
  • Familiar

Proposed Solutions: ggvfields

Install from Github

remotes::install_github("dusty-turner/ggvfields")

Load the package

library(ggvfields)

geom_vector_field()

Let’s explore the vector field defined by the function:

\[\mathbf{V}(x,y) = (-y, x)\]

f <- function(v) {
  x <- v[1]
  y <- v[2]
  c(-y, x)
}

A very simple and familiar implementation

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10)) 

geom_vector_field(): Implementation

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10)) 

add title

ggplot() + coord_equal() + 
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10)) +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), center = FALSE, color = "red") 

geom_vector_field(): Center

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), center = FALSE) 

geom_vector_field(): Normalize

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), normalize = FALSE) 

geom_vector_field(): Other Aesthetics

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(color = after_stat(norm))
  ) 

geom_vector_field(): Other Aesthetics

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(alpha = after_stat(norm))
  ) 

geom_vector_field(): Other Aesthetics

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(linewidth = after_stat(norm))
  ) 

Calculus Concepts in Vector Fields

\(\mathbf{F} = \langle \mathbf{F}_x(x,y), \mathbf{F}_y(x,y) \rangle\)

Divergence

The divergence of a vector field \(\mathbf{F}\) in \(\mathbb{R}^2\) is defined by: \[\text{div} \, \mathbf{F} = \frac{\partial \mathbf{F}_x}{\partial x} + \frac{\partial \mathbf{F}_y}{\partial y}\] Indicates how much the vector field spreads out or converges at a point.

Curl

The curl of a vector field \(\mathbf{F}\) in \(\mathbb{R}^2\) is defined by: \[\text{curl} \, \mathbf{F} = \frac{\partial \mathbf{F}_y}{\partial x} - \frac{\partial \mathbf{F}_x}{\partial y}\] Measures the rotation or swirling strength at a point.

Laplace Operator

The Laplacian of the vector field \(\mathbf{F}\) is given by: \[\Delta \mathbf{F} = \frac{\partial^2 \mathbf{F}_x}{\partial x^2} + \frac{\partial^2 \mathbf{F}_x}{\partial y^2} + \frac{\partial^2 \mathbf{F}_y}{\partial x^2} + \frac{\partial^2 \mathbf{F}_y}{\partial y^2}\] Describes how the vector field spreads out or compresses at different points.

Directional Derivative

The directional derivative of a vector field measures the rate of change of the field in a specified direction. It is given by: \[D_{\mathbf{v}} \mathbf{F} = \frac{\partial \mathbf{F}_x}{\partial x} v_x + \frac{\partial \mathbf{F}_x}{\partial y} v_y + \frac{\partial \mathbf{F}_y}{\partial x} v_x + \frac{\partial \mathbf{F}_y}{\partial y} v_y\] Represents the rate of change of each component of the field in a given direction.

geom_vector_field(): Divergence

ggplot() +
  geom_vector_field(fun = f , xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(color = after_stat(divergence))
  ) 

geom_vector_field(): Curl

ggplot() +
  geom_vector_field(fun = f , xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(color = after_stat(curl))
  ) 

geom_vector_field(): Laplace Operator

g <- function(v) {x <- v[1]; y <- v[2]; c(-sin(y), cos(x))}

ggplot() +
  geom_vector_field(fun = g , xlim = c(-10, 10), ylim = c(-10, 10), 
    aes(color = after_stat(laplacian))
  ) 

geom_vector_field(): Multiple Layers

ggplot() +
  geom_vector_field(fun = \(v) c(v[1], -v[2]) , xlim = c(-10, 10), ylim = c(-10, 10)) +
  geom_vector_field(fun = f , xlim = c(-10, 10), ylim = c(-10, 10), color = "red") +
  coord_equal()

geom_vector_field(): Future Work

Length Aesthetic

ggplot() +
  geom_vector_field(fun = f, xlim = c(-10, 10), ylim = c(-10, 10),
    aes(color = after_stat(norm), 
        length = after_stat(norm)
        )     
    ) +
  scale_length_continuous(guide = "legend") # vs "none"

geom_vector_field(): Future Work

Length Aesthetic

geom_vector_field(): Future Work

Length Aesthetic: Current Issues

geom_vector_field(): Future Work

Length Aesthetic: Current Issues

geom_vector_field(): Future Work

Future Work: What Should I Call This?

geom_vector_field(): Future Work

Future Work: What Should I Call This?

Revisit the Problem: R

How else could we visualize this vector field in R?

\[\mathbf{f}(x,y) = (-y, x)\]

Revisit the Problem: R

Revisit the Problem: R

Revisit the Problem: R

what are the mathematical detials ## Current Solutions: Python

import numpy as np
import matplotlib.pyplot as plt

Y, X = np.mgrid[-3:3:100j, -3:3:100j]

U = -1 - X**2 + Y
V = 1 + X - Y**2

plt.streamplot(X, Y, U, V)
plt.show()

Current Solutions: Python

Current Solutions: Mathematica

StreamPlot[{-1 - x^2 + y, 1 + x - y^2}, {x, -3, 3}, {y, -3, 3}]

geom_streamplot(): Introduction

How to plot this in R?

\[\mathbf{f}(x,y) = (-1 - x^2 + y, 1 + x - y^2)\]

f <- function(v) {
  x <- v[1]
  y <- v[2]
  c(-1 - x^2 + y, 1 + x - y^2)
}
  1. Pick a starting point
  2. Trace the vector throughout the region
  3. Repeat until the region is sufficiently filled with streamlines

This sounds a lot like…

Euler’s method

geom_streamplot(): Euler’s Method

euler_integrate <- function(xi, yi, f, ds) {

  while (is_inside_plot) {
    uv <- f(c(xi, yi))
    u <- uv[1]
    v <- uv[2]
    dx <- ds * (u / norm)
    dy <- ds * (v / norm)
    xi <- xi + dx
    yi <- yi + dy
    
    xy_traj <- append(xy_traj, list(c(xi, yi)))
  }
}

Euler’s method steps:

  1. Start with the initial conditions \((x_0, y_0)\).

  2. Choose a step size \(h\).

  3. Compute for \(n = 0, 1, 2, \ldots\)

  • \(x_{n+1} = x_n + h \cdot f_1(x_n, y_n)\)

  • \(y_{n+1} = y_n + h \cdot f_2(x_n, y_n)\)

  1. Set termination condition

geom_streamplot(): Euler’s Method

geom_streamplot(): Euler’s Method

geom_streamplot(): Euler’s Method

geom_streamplot(): Euler’s Method

Considerations

  • Where do we draw these streams?

geom_streamplot(): Termination Conditions

Considerations

  • Where do we draw these streams?
  • We don’t want to allow them to get too close

geom_streamplot(): Termination Conditions

Considerations

  • Where do we draw these streams?
  • We don’t want to allow them to get too close

geom_streamplot(): Termination Conditions

show

  • inset square
  • inset circle

geom_streamplot(): Implementation

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3)) +
  coord_fixed() 

geom_streamplot(): chop

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), chop = FALSE) +
  coord_fixed() 

geom_streamplot(): scale_stream

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), scale_stream = 2) +
  coord_fixed()

geom_streamplot(): scale_stream

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), scale_stream = .5) +
  coord_fixed()

geom_streamplot(): n

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), n = 10) +
  coord_fixed()

geom_streamplot(): n

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), n = 30, scale_stream = 3) +
  coord_fixed()

geom_streamplot(): mask_shape_type

ggplot() +
  geom_streamplot(fun = f, xlim = c(-3, 3), ylim = c(-3, 3), mask_shape_type = "diamond") +
  coord_fixed()

geom_streamplot(): mask_shape_type

geom_streamplot(): Animation

Question: Should I show how this function works?

note: would need to redo this data so that it move uniformly across each vector

p <- ggplot() +
  geom_streamplot(
    aes(rownum = after_stat(rownum)), 
    fun = f, xlim = c(-3, 3), ylim = c(-3, 3)
    ) +
  coord_fixed() +
  theme_bw()

# Create an animation transition plot
anim <- 
  animation_transition(plot = p) +   
  transition_reveal(rownum) +
  ease_aes('linear')

# Animate the plot
animate(anim, nframes = 25, fps = 5, end_pause = 0, renderer = gifski_renderer())

geom_streamplot(): Animation

geom_streamplot(): Future Work

Color by:

  • Magnitude
  • Curl
  • Divergence
  • Laplacian

Future Work: Complex Function Visualization

Explain what a complex function is

Future Work: geom_complex_function()

f <- function(z) (z^2 + 1) / (z^2 - 1)

ggplot() +
  geom_complex_function(fun = f, relim = c(-2, 2), imlim = c(-2, 2), n = 100) +
  labs(x = "Real", y = "Imaginary") +
  coord_fixed() +
  theme(legend.box = "horizontal")

Future Work: geom_complex_function()

Future Work

ggvfields

External

  1. Vignettes
  2. Publish on CRAN
  3. Publish in R Journal
  4. Hex Sticker

Internal

  1. geom_vector_field()
    • Length aesthetic
    • Vector interpolation
  2. geom_stream_plot()
    • Color by calculus measure
  3. geom_complex_function()
    • Complete development

Future Work

Data Recovery

mtcars |>
  ggplot(aes(hp, mpg)) +
  geom_point()

Parting Words

expected release data (31 OCT)

other questions

where to put ggquiver and what to say about it

Where/how to put some picture of help/documentation

create a streamplot with no mask

when to do vignettes?